package com.ltx.blog_ltx.until;

import com.ltx.blog_ltx.entity.dto.DoOjTable;
import com.ltx.blog_ltx.entity.dto.OJDto;
import com.ltx.blog_ltx.mapper.OJMapper;
import com.ltx.blog_ltx.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.*;

@Component
public class ItemSimilarity {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private OJMapper ojMapper;

    private static ItemSimilarity itemSimilarity;

    @PostConstruct
    public void init(){
        itemSimilarity=this;
        itemSimilarity.userMapper=this.userMapper;
        itemSimilarity.ojMapper=this.ojMapper;
    }

    public static ArrayList<OJDto> recommend(int userId){
        ArrayList<DoOjTable> DoOJLists;    //其他用户做题列表

        List<Integer> userIds = itemSimilarity.userMapper.AllUserId();    //用户名列表
        List<OJDto> ojDtos = itemSimilarity.ojMapper.AllOj();             //所有的oj题目信息
        int[][] curMatrix = new int[ojDtos.size()+5][ojDtos.size()+5];   //当前矩阵
        int[][] comMatrix = new int[ojDtos.size()+5][ojDtos.size()+5];   //共现矩阵
        int[] N=new int[ojDtos.size()+5];    //每个题目做题的人数

        for (Integer id : userIds) {
            if(id==userId) continue;      //当前用户就跳过
            DoOJLists=itemSimilarity.ojMapper.DoOjByUserId(id);  //当前用户做题列表
            System.out.println(DoOJLists);
            for(int i=0;i<ojDtos.size();i++)
                for (int j=0;j<ojDtos.size();j++)
                    curMatrix[i][j] = 0;                        //清空矩阵

            for(int i=0;i<DoOJLists.size();i++) {
                int ojId1 = DoOJLists.get(i).getOjId();
                ++N[ojId1];
                for(int j =i+1;j<DoOJLists.size();j++){
                    int ojId2 = DoOJLists.get(j).getOjId();
                    ++curMatrix[ojId1][ojId2];
                    ++curMatrix[ojId2][ojId1]; //两两加一
                }
            }
            //累加所有矩阵, 得到共现矩阵
            for(int i=0;i<ojDtos.size();i++) {
                for (int j = 0; j < ojDtos.size(); j++) {
                    int ojId1 = ojDtos.get(i).getId(),ojId2 = ojDtos.get(j).getId();
                    comMatrix[ojId1][ojId2] += curMatrix[ojId1][ojId2];
                    comMatrix[ojId2][ojId1] += curMatrix[ojId2][ojId1];
                }
            }
        }

        TreeSet<OJDto> ojList =new TreeSet<OJDto>(new Comparator<OJDto>() {
            @Override
            public int compare(OJDto o1, OJDto o2) {
                if(o1.getW()!=o2.getW()){
                    return (int) (o1.getW()-o2.getW())*100;
                }
                else
                    return o1.getSubmitNum()-o2.getSubmitNum();
            }
        }); //预处理的列表


        for(int i=0;i<ojDtos.size()+5;i++) {
            for (int j = 0; j < ojDtos.size()+5; j++) {
                System.out.print(comMatrix[i][j]);
            }
            System.out.println();
        }
        DoOJLists = itemSimilarity.ojMapper.DoOjByUserId(userId); //当前用户喜欢的论文列表
        boolean[] used = new boolean[ojDtos.size()+5];  //判重数组
        for (DoOjTable doOJList : DoOJLists) {
            int Nij=0;                      //既喜欢i又喜欢j的人数
            double Wij;                     //相似度
            OJDto tmp;                      //当前的题目

            int i=doOJList.getOjId();
            for (OJDto ojDto : ojDtos) {
                if(doOJList.getOjId()==ojDto.getId()) continue;
                int j=ojDto.getId();

                Nij = comMatrix[i][j];
                Wij = (double)Nij/Math.sqrt(N[i]*N[j]);     //计算余弦相似度

                tmp = itemSimilarity.ojMapper.NowOjDto(ojDto.getId());
                tmp.setW(Wij);

                if(used[tmp.getId()]) continue;
                ojList.add(tmp);
                used[tmp.getId()] = true;
            }
        }

        System.out.println(ojList);
        ArrayList<Integer> doOJListId = new ArrayList<>();
        for (DoOjTable doOJList : DoOJLists) {
            doOJListId.add(doOJList.getOjId());
        }
        ArrayList<OJDto> recomLists = new ArrayList<>();      //生成的推荐结果
        for(int i=0;ojList.size()>0 && i<5;i++){
                if(!doOJListId.contains(ojList.last().getId())){     //题目不可以是用户做过的题目
                    recomLists.add(ojList.pollLast());
                    ojList.pollLast();
            }else {
                    ojList.pollLast();
                }

        }
        System.out.println(recomLists);
        if (recomLists.size()<5){
            //推荐数量不满5个, 补足喜欢数最高的文章，但是文章不可以是已经推荐了的里面的
            List<OJDto> ojDtos1 = itemSimilarity.ojMapper.ojTopSum(5 - recomLists.size(),recomLists);
            recomLists.addAll(ojDtos1);
        }
        return recomLists; //返回推荐列表
    }

    /***
     * 当用户做题量只有不到15%的时候就只给用户随机推荐简单题目
     * @param userId 用户id（用来过滤不给用户推荐用户做过的题目的）
     * @return
     */
    public  static List<OJDto> RandomSimplicity(int userId){

        ArrayList<DoOjTable> doOjTables = itemSimilarity.ojMapper.DoOjByUserId(userId);    //用户做过的所有题目
        List<OJDto> ojDtos = itemSimilarity.ojMapper.AllSimplicityOj(doOjTables);           //获取用户没有做过的所有简单题目的list
        Collections.shuffle(ojDtos);       //打乱列表
        return ojDtos.subList(0,5);        //返回前五个元素，也就是随机返回用户没有做过的五个简单题目
    }
}
